package com.smh.demo1.a14;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.Order;

import java.util.List;

/**
 * @author shiminghui
 * @date 2025/4/16 22:08
 * @description: TODO
 */
public class A14Application {

    public static void main(String[] args) {

        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("MyAspect", MyAspect.class);
        context.registerBean("config", Config.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.registerBean(Target.class); // 创建一个Target对象

        context.registerBean(TestAnnotationAwareAspectJAutoProxyCreator.class);

        context.refresh();
        System.out.println("----------------------");
        TestAnnotationAwareAspectJAutoProxyCreator bean = context.getBean(TestAnnotationAwareAspectJAutoProxyCreator.class);
        // findEligibleAdvisors方法会找到匹配的Advisor集合,低级advisor会直接加入集合,高级advisor会转化为多个Advisor加入集合
        List<Advisor> advisors = bean.find(Target.class, "test");
        for (Advisor advisor : advisors) {
            System.out.println(advisor);
        }
        System.out.println("--------------------");
        Object wrap = bean.wrap(new Target(), "target", "cacheKey");
        // 拿到了一个代理对象
        // wrapIfNecessary 方法会调用findEligibleAdvisors,如果集合为空,则返回原始对象,否则返回代理对象
        System.out.println("wrap = " + wrap.getClass().getName());

        System.out.println("==========================");
        Target bean1 = context.getBean(Target.class);
        bean1.read(1);


    }

    // 这里继承使用是因为父类的方法是受保护的
    static class TestAnnotationAwareAspectJAutoProxyCreator extends AnnotationAwareAspectJAutoProxyCreator {
        public List<Advisor> find(Class clazz, String beanName) {
            List<Advisor> eligibleAdvisors = super.findEligibleAdvisors(clazz, beanName);
            return eligibleAdvisors;
        }

        public Object wrap(Object bean, String beanName, String cacheKey) {
            Object o = super.wrapIfNecessary(bean, beanName, cacheKey);
            return o;
        }
    }

    static class Target {
        public void test() {

        }

        public void read(int sum) {
            System.out.println("read");
        }
    }

    @Aspect
    @Order(1) // 调整执行顺序
    static class MyAspect {

        @Before("execution(* read(..))")
        public void before() {
            System.out.println("MyAspect before");
        }

        @After("execution(* read(..))")
        public void after() {
            System.out.println("MyAspect after");
        }

    }

    @Configuration
    static class Config {
        @Bean
        public DefaultPointcutAdvisor advisor(MethodInterceptor methodInterceptor) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* read(..))");
            DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, methodInterceptor);
            advisor.setOrder(2);
            return advisor;
        }

        @Bean
        public MethodInterceptor methodInterceptor() {
            return new MethodInterceptor() {
                @Override
                public Object invoke(MethodInvocation invocation) throws Throwable {
                    System.out.println("advisor before");
                    Object o = invocation.proceed();
                    System.out.println("advisor after");
                    return o;
                }
            };
        }
    }


}
